<script>
export default {
  name: 'FormCreate',
  props: {
    conf: {
      type: Object,
      required: true,
    },
    nonCheck: {
      //判断是否不验 传true不验 false验
      type: Boolean,
      default: () => false,
    },
    isAdded: {
      //判断是否是添加  传true 添加 false 修改或者回显
      type: Boolean,
      required: true,
    },
    look: {
      //判断是否查看 传true 为仅查看
      type: Boolean,
      default: () => false,
    },
  },
  watch: {
    // 判断是报告的查看还是编辑
    isEcho: {
      deep: true,
      immediate: true,
      handler(newVal) {
        let isEchoVal = []
        for (const key in newVal) {
          isEchoVal.push(newVal[key])
        }
        this.newIsEcho = isEchoVal.some((i) => i == false)
        if (this.newIsEcho) {
          // 编辑
          this.$emit('editViewReport', false)
        } else {
          // 查看
          this.$emit('editViewReport', true)
        }
      },
    },
  },
  data() {
    return {
      form: {}, // Vue2中新增属性，默认不是响应式=数据改变+页面变化  => $set
      fileList: [],
      oldFileList: [],
      inputValue: '',
      oldFromEdit: [],
      dynamicTags: [],
      fileListLength: 0,
      newIsEcho: null,
      isEcho: {},
      sureImage: require('@/assets/image/index/icon_gou.png'),
      cancelImage: require('@/assets/image/index/icon_cha.png'),
    }
  },
  created() {
    const { items, cards, rules } = this.conf
    const { nonCheck, isAdded } = this
    // 尽量用false属性来增加, 只有新增的东西才多这个true属性
    if (!nonCheck && !rules) throw new Error('看文档,哪个表单不验证啊？')
    this.rulesHandler(rules)
    if (items) {
      this.reaciveFileds(items, isAdded)
    } else if (cards) {
      cards.forEach((card) => {
        if (card.children) {
          this.reaciveFileds(card.children, isAdded)
        }
      })
    }
  },
  render() {
    //疯狂解构
    const { items, rules, labelWidth } = this.conf
    const { form, sureImage, cancelImage } = this
    return (
      <div class="form-box">
        {/*表单区域：JSX不能直接传递model属性 */}
        <el-form
          ref="form"
          attrs={{ model: form }}
          rules={rules}
          label-width={labelWidth}
        >
          {this.renderRows(items)}
        </el-form>
        {/* btns 按钮 */}
        <div class="btns center-fix">
          {/*仅仅填dom */}
          {this.$slots.default ? (
            this.$slots.default
          ) : (
            <div class="btn_groups">
              <div class="cancel" onClick={() => this.reset()}>
                <img src={cancelImage} />
                <span>取消</span>
              </div>
              {this.newIsEcho || this.isAdded ? (
                <div class="success" onClick={() => this.doSubmit()}>
                  <img src={sureImage} />
                  <span>确定</span>
                </div>
              ) : null}
            </div>
          )}
          {/*仅仅填dom,给父传递参数 this.$scopedSlots.default(data) */}
        </div>
      </div>
    )
  },
  methods: {
    reaciveFileds(items, isAdded) {
      items.forEach((rowArr) => {
        rowArr.forEach((item) => {
          // 判断是否是添加
          if (isAdded) {
            this.$set(item, 'isAdd', true) //判断是是添加
            this.$set(item, 'disabled', false)
            if (item.type == 'dynamicEditTag') {
              this.$set(item, 'inputVisible', false)
              this.$set(item, item.key, [])
              this.$set(this.form, item.key, [])
            }
          } else {
            if (!this.look) {
              this.$set(item, 'isAdd', false) // 回显、编辑
              this.$set(item, 'disabled', true)
              this.$set(this.isEcho, item.key, item.disabled)
            } else {
              this.$set(item, 'isAdd', true) // 回显
              this.$set(item, 'disabled', true)
            }
            if (item.type == 'dynamicEditTag') {
              this.$set(this.form, item.key, item.value)
              this.$set(this, 'dynamicTags', item.value)
            }
          }
          if (item.type == 'files') {
            this.fileList = item.value
          } else {
            this.$set(this.form, item.key, item.value)
          }
        })
      })
    },
    rulesHandler(rules) {
      // 改变自定义验证器的this指向，箭头函数无法被改变
      for (const key in rules) {
        let valArr = rules[key]
        valArr.forEach((item) => {
          if (item.validator) {
            item.validator = item.validator.bind(this)
          }
        })
      }
    },
    renderRows(rows) {
      return rows.map((rowArr) => {
        return <el-row> {this.renderColums(rowArr)}</el-row>
      })
    },
    renderColums(columns) {
      return columns.map((item) => {
        return (
          <el-col
            xl={item.colspan}
            lg={item.colspan}
            md={item.colspan}
            sm={item.colspan}
            xs={item.colspan}
            style={item.elColStyle}
          >
            <el-form-item
              label={item.label}
              label-width={item.labelWidth}
              prop={item.key}
              style={item.ElFormItemStyle}
            >
              {this.renderItem(item)}
            </el-form-item>
          </el-col>
        )
      })
    },
    //编辑
    inputBoxEdit(renderItemEdit, fromEdit) {
      if (renderItemEdit.type == 'files') {
        // 因为原来的fileList没有发生变化，再重新赋值时无法触发vue的数据响应式逻辑，导致上传组件内部的watch没有被触发。
        // 解决办法： 赋值时赋值一个全新的对象数组即可（只要引用发生变化即可。）
        // 切记这个地方不能使用 JSON.parse(JSON.stringify()) 进行拷贝，因为  JSON.parse(JSON.stringify()) 会把 raw 的 File 变成 Object， 所以这个地方只能使用浅拷贝
        console.log(fromEdit)
        this.oldFromEdit[renderItemEdit.key] = [...fromEdit]
      } else if (renderItemEdit.type === 'dynamicEditTag') {
        this.oldFromEdit[renderItemEdit.key] = [...fromEdit]
      } else {
        this.oldFromEdit[renderItemEdit.key] = fromEdit[renderItemEdit.key]
      }
      this.isEcho[renderItemEdit.key] = false
      renderItemEdit.disabled = false
    },
    // 取消
    inputBoxEditCancel(renderItemEdit) {
      if (renderItemEdit.type == 'files') {
        this.fileList = this.oldFromEdit[renderItemEdit.key]
        this.$emit(
          'inputBoxEditCancelFiles',
          this.oldFromEdit[renderItemEdit.key]
        )
      } else if (renderItemEdit.type === 'dynamicEditTag') {
        this.dynamicTags = this.oldFromEdit[renderItemEdit.key]
      } else {
        this.form[renderItemEdit.key] = this.oldFromEdit[renderItemEdit.key]
      }
      this.isEcho[renderItemEdit.key] = true
      renderItemEdit.disabled = true
    },
    renderTextarea(renderItems, renderFrom) {
      return renderItems.type == 'textarea' ? (
        <div style={{ display: 'flex' }}>
          <el-input
            attrs={renderItems.attrs}
            style={{ marginRight: '10px' }}
            type={renderItems.type}
            v-model={renderFrom[renderItems.key]}
            disabled={renderItems.disabled}
          />
          <div>
            {renderItems.disabled ? (
              <el-button
                class="cancel"
                onClick={() => this.inputBoxEdit(renderItems, renderFrom)}
              >
                编辑
              </el-button>
            ) : (
              <el-button
                class="cancel"
                onClick={() => this.inputBoxEditCancel(renderItems)}
              >
                取消
              </el-button>
            )}
          </div>
        </div>
      ) : (
        <div style={{ display: 'flex' }}>
          <el-input
            attrs={renderItems.attrs}
            style={{ marginRight: '10px' }}
            type={renderItems.type}
            v-model={renderFrom[renderItems.key]}
            disabled={renderItems.disabled}
          />
          {renderItems.disabled ? (
            <el-button
              class="cancel"
              onClick={() => this.inputBoxEdit(renderItems, renderFrom)}
            >
              编辑
            </el-button>
          ) : (
            <el-button
              class="cancel"
              onClick={() => this.inputBoxEditCancel(renderItems)}
            >
              取消
            </el-button>
          )}
        </div>
      )
    },
    renderItem(item) {
      const { fileList } = this
      switch (item.type) {
        case 'input':
        case 'password':
        case 'textarea':
          return item.isAdd ? (
            <el-input
              attrs={item.attrs}
              disabled={item.disabled}
              type={item.type}
              v-model={this.form[item.key]}
            />
          ) : (
            this.renderTextarea(item, this.form)
          )
        case 'radio':
          return item.options.map((opt, i) => {
            return (
              <el-radio
                disabled={item.disabled}
                attrs={item.attrs}
                key={i}
                v-model={this.form[item.key]}
                label={opt.label}
              >
                {opt.text}
              </el-radio>
            )
          })
        case 'select':
          return item.isAdd ? (
            <el-select
              disabled={item.disabled}
              style={{ width: '100% !important' }}
              attrs={item.attrs}
              v-model={this.form[item.key]}
              multiple={item.multiple}
              collapse-tags={item.collapseTags}
            >
              {item.options.map((opt) => {
                return (
                  <el-option
                    key={opt.value}
                    label={opt.label}
                    value={opt.value}
                  />
                )
              })}
            </el-select>
          ) : (
            <div style={{ display: 'flex' }}>
              <el-select
                attrs={item.attrs}
                v-model={this.form[item.key]}
                multiple={item.multiple}
                style={{ marginRight: '10px', width: '100% !important' }}
                disabled={item.disabled}
                collapse-tags={item.collapseTags}
              >
                {item.options.map((opt) => {
                  return (
                    <el-option
                      key={opt.value}
                      label={opt.label}
                      value={opt.value}
                    />
                  )
                })}
              </el-select>
              {item.disabled ? (
                <el-button
                  class="cancel"
                  onClick={() => this.inputBoxEdit(item, this.from)}
                >
                  编辑
                </el-button>
              ) : (
                <el-button
                  class="cancel"
                  onClick={() => this.inputBoxEditCancel(item)}
                >
                  取消
                </el-button>
              )}
            </div>
          )
        case 'datetime':
          return item.isAdd ? (
            <el-date-picker
              disabled={item.disabled}
              attrs={item.attrs}
              style={{ width: '100% !important' }}
              v-model={this.form[item.key]}
              type="date"
              placeholder="选择日期"
            />
          ) : (
            <div style={{ display: 'flex' }}>
              <el-date-picker
                attrs={item.attrs}
                disabled={item.disabled}
                style={{ marginRight: '10px', width: '100% !important' }}
                v-model={this.form[item.key]}
                type="date"
                placeholder="选择日期"
              />
              {item.disabled ? (
                <el-button
                  class="cancel"
                  onClick={() => this.inputBoxEdit(item, this.from)}
                >
                  编辑
                </el-button>
              ) : (
                <el-button
                  class="cancel"
                  onClick={() => this.inputBoxEditCancel(item)}
                >
                  取消
                </el-button>
              )}
            </div>
          )
        case 'daterange':
          return item.isAdd ? (
            <el-date-picker
              disabled={item.disabled}
              style={{ width: '100% !important' }}
              popper-class="elDatePicker"
              attrs={item.attrs}
              v-model={this.form[item.key]}
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              value-format="yyyy-MM-dd"
            />
          ) : (
            <div style={{ display: 'flex' }}>
              <el-date-picker
                style={{ marginRight: '10px', width: '100% !important' }}
                popper-class="elDatePicker"
                disabled={item.disabled}
                attrs={item.attrs}
                v-model={this.form[item.key]}
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                value-format="yyyy-MM-dd"
              />
              {item.disabled ? (
                <el-button
                  class="cancel"
                  onClick={() => this.inputBoxEdit(item, this.from)}
                >
                  编辑
                </el-button>
              ) : (
                <el-button
                  class="cancel"
                  onClick={() => this.inputBoxEditCancel(item)}
                >
                  取消
                </el-button>
              )}
            </div>
          )
        case 'files':
          return item.isAdd ? (
            <fragment>
              {item.disabled ? (
                // 查看
                <el-upload
                  class="disableUpload" //隐藏 el-upload 加号
                  disabled={item.disabled}
                  action={item.action}
                  list-type="picture-card"
                  multiple={item.multiple}
                  autoUpload={item.autoUpload}
                  limit={item.limit} //最大允许上传个数
                  attrs={item.attrs}
                  fileList={fileList}
                >
                  <i class="el-icon-plus" />
                </el-upload>
              ) : (
                <fragment>
                  {this.fileListLength === item.limit ? (
                    <el-upload
                      // 添加大于 item.limit 时隐藏 el-upload 加号
                      class="disableUpload"
                      disabled={item.disabled}
                      action={item.action}
                      list-type="picture-card"
                      multiple={item.multiple}
                      autoUpload={item.autoUpload}
                      limit={item.limit} //最大允许上传个数
                      attrs={item.attrs}
                      fileList={fileList}
                    >
                      <i class="el-icon-plus" />
                      <div
                        slot="tip"
                        class="el-upload__tip"
                        style={{ color: '#fff' }}
                      >
                        只能上传jpg/png文件,且最多只能上传 {item.limit} 张{' '}
                      </div>
                    </el-upload>
                  ) : (
                    <el-upload // 添加
                      disabled={item.disabled}
                      action={item.action}
                      list-type="picture-card"
                      multiple={item.multiple}
                      autoUpload={item.autoUpload}
                      limit={item.limit} //最大允许上传个数
                      attrs={item.attrs}
                      fileList={fileList}
                    >
                      <i class="el-icon-plus" />
                      <div
                        slot="tip"
                        class="el-upload__tip"
                        style={{ color: '#fff' }}
                      >
                        只能上传jpg/png文件,且最多只能上传 {item.limit} 张{' '}
                      </div>
                    </el-upload>
                  )}
                </fragment>
              )}
            </fragment>
          ) : (
            <fragment>
              {/* 查看 编辑 */}
              <div style={{ float: 'right' }}>
                {item.disabled ? (
                  <el-button
                    class="cancel"
                    onClick={() => this.inputBoxEdit(item, fileList)}
                  >
                    编辑
                  </el-button>
                ) : (
                  <el-button
                    class="cancel"
                    onClick={() => this.inputBoxEditCancel(item)}
                  >
                    取消
                  </el-button>
                )}
              </div>
              {item.disabled ? (
                // 查看
                <el-upload
                  class="disableUpload" //隐藏 el-upload 加号
                  disabled={item.disabled}
                  attrs={item.attrs}
                  fileList={fileList}
                  action={item.action}
                  limit={item.limit} //最大允许上传个数
                  list-type="picture-card"
                  multiple={item.multiple}
                  autoUpload={item.autoUpload}
                >
                  <i class="el-icon-plus" />
                </el-upload>
              ) : (
                <fragment>
                  {this.fileListLength === item.limit ? (
                    <el-upload
                      class="disableUpload" // 编辑大于 item.limit 时隐藏 el-upload 加号
                      disabled={item.disabled}
                      attrs={item.attrs}
                      fileList={fileList}
                      limit={item.limit} //最大允许上传个数
                      action={item.action}
                      list-type="picture-card"
                      multiple={item.multiple}
                      autoUpload={item.autoUpload}
                    >
                      <i class="el-icon-plus" />
                      <div
                        slot="tip"
                        class="el-upload__tip"
                        style={{ color: '#fff' }}
                      >
                        只能上传jpg/png文件,且最多只能上传5张
                      </div>
                    </el-upload>
                  ) : (
                    <el-upload // 编辑
                      disabled={item.disabled}
                      attrs={item.attrs}
                      fileList={fileList}
                      limit={item.limit} //最大允许上传个数
                      action={item.action}
                      list-type="picture-card"
                      multiple={item.multiple}
                      autoUpload={item.autoUpload}
                    >
                      <i class="el-icon-plus" />
                      <div
                        slot="tip"
                        class="el-upload__tip"
                        style={{ color: '#fff' }}
                      >
                        只能上传jpg/png文件,且最多只能上传5张
                      </div>
                    </el-upload>
                  )}
                </fragment>
              )}
            </fragment>
          )
        case 'dynamicEditTag': //动态编辑标签
          return item.isAdd ? (
            <fragment>
              {this.dynamicTags.map((tag) => (
                <el-tag
                  key={tag}
                  closable={item.disabled ? false : true}
                  disable-transitions={item.disableTransitions}
                  onClose={() => this.handleClose(tag, this.form, item.key)}
                >
                  {tag}
                </el-tag>
              ))}
              {item.inputVisible ? (
                <el-input
                  class="input-new-tag"
                  v-model={this.inputValue}
                  ref={'saveTagInput'}
                  size={item.size}
                  onKeyUp={() =>
                    this.handleInputConfirm(item, this.form, item.key)
                  }
                  onBlur={() =>
                    this.handleInputConfirm(item, this.form, item.key)
                  }
                />
              ) : (
                <el-button
                  class="button-new-tag"
                  size={item.size}
                  onClick={() =>
                    this.showInput(item, this.form, item.key, this.dynamicTags)
                  }
                >
                  新Tag
                </el-button>
              )}
            </fragment>
          ) : (
            <fragment>
              {item.disabled ? (
                <fragment>
                  {this.dynamicTags.map((tag) => (
                    <el-tag
                      key={tag}
                      closable={item.disabled ? false : true}
                      disable-transitions={item.disableTransitions}
                      onClose={() => this.handleClose(tag, this.form, item.key)}
                    >
                      {tag}
                    </el-tag>
                  ))}
                </fragment>
              ) : (
                <fragment>
                  {this.dynamicTags.map((tag) => (
                    <el-tag
                      key={tag}
                      closable={item.disabled ? false : true}
                      disable-transitions={item.disableTransitions}
                      onClose={() => this.handleClose(tag, this.form, item.key)}
                    >
                      {tag}
                    </el-tag>
                  ))}
                  {item.inputVisible ? (
                    <el-input
                      class="input-new-tag"
                      v-model={this.inputValue}
                      ref={'saveTagInput'}
                      size={item.size}
                      onKeyUp={() =>
                        this.handleInputConfirm(item, this.form, item.key)
                      }
                      onBlur={() =>
                        this.handleInputConfirm(item, this.form, item.key)
                      }
                    />
                  ) : (
                    <el-button
                      class="button-new-tag"
                      size={item.size}
                      onClick={() =>
                        this.showInput(
                          item,
                          this.form,
                          item.key,
                          this.dynamicTags
                        )
                      }
                    >
                      新Tag
                    </el-button>
                  )}
                </fragment>
              )}
              {item.disabled ? (
                <el-button
                  style={{ float: 'right' }}
                  class="cancel"
                  onClick={() => this.inputBoxEdit(item, this.dynamicTags)}
                >
                  编辑
                </el-button>
              ) : (
                <el-button
                  style={{ float: 'right' }}
                  class="cancel"
                  onClick={() => this.inputBoxEditCancel(item)}
                >
                  取消
                </el-button>
              )}
            </fragment>
          )
      }
    },
    validate(fn) {
      // 1. 先验证， 验证通过 调用this.getData()作为参数给fn
      // 2. 验证失败 返回false或者null给外部
      this.$refs.form.validate((valid) => {
        if (valid) {
          fn(this.getData())
        } else {
          fn(false)
        }
      })
    },
    getData() {
      return this.deepClone(this.form)
    },
    reset() {
      this.$refs.form.resetFields()
      this.fileList = []
      this.$emit('reset')
    },
    deepClone(data) {
      return JSON.parse(JSON.stringify(data))
    },
    doSubmit() {
      let { submit } = this.$listeners //@submit //方式一
      //需要验证
      this.validate(submit)
      // this.$emit("submit", this.deepClone(this.form));//方式二
    },
    fileListData(fileList) {
      // 因为 fileList 没有被引用，所以需要一个变量去接收
      this.fileListLength = fileList.length
      this.form.files = fileList
    },
    handleClose(tag, form, key) {
      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1)
      this.$set(form, key, [...this.dynamicTags])
    },
    showInput(item, form, key, dynamicTags) {
      this.$set(item, 'inputVisible', true)
      this.$set(form, key, [...dynamicTags])
    },
    handleInputConfirm(item, form, key) {
      let inputValue = this.inputValue
      if (inputValue) {
        this.dynamicTags.push(inputValue)
        form[key].push(inputValue)
      }
      this.$set(item, 'inputVisible', false)
      this.inputValue = ''
    },
  },
}
</script>
<style lang="less" scoped>
.btn_groups {
  color: #fff;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;

  div {
    width: 120px;
    height: 45px;
    line-height: 45px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
  }

  .cancel {
    margin-right: 20px;
    background-color: rgb(0, 117, 169);

    img {
      margin-right: 10px;
      width: 22px;
      height: 22px;
    }
  }

  .success {
    background-color: rgb(235, 97, 0);

    img {
      margin-right: 10px;
      width: 28px;
      height: 18px;
    }
  }
}

.cancel {
  background-color: rgb(0, 117, 169);
  color: #fff;
  border: none;
  border-radius: 10px;
}

.success {
  background-color: rgb(235, 97, 0);
  color: #fff;
  border: none;
  border-radius: 10px;
}

:deep(.el-form-item__label) {
  color: #fff;
}

:deep(.el-input__inner) {
  background-color: rgba(9, 25, 58, 0.43);
  color: #fff;

  &:focus {
    border-color: #dcdfe6;
  }
}

// 时间选择器样式
:deep(.el-picker-panel) {
  background: rgba(0, 117, 169, 0.2) !important;
}

:deep(.el-date-editor) {
  .el-range-input {
    background-color: transparent;
    color: #fff;
  }

  .el-range-separator {
    color: #fff;
  }

  .el-range__icon {
    color: #fff;
  }
}

:deep(.el-range-editor) {
  &.is-active {
    border-color: #dcdfe6;

    &hover {
      border-color: #dcdfe6;
    }
  }
}

//下拉框
.el-select {
  .el-input__inner {
    &:focus {
      border-color: #dcdfe6;
    }
  }
}

:deep(.el-select__tags) {
  max-width: 100% !important;
}

:deep(.el-upload--picture-card) {
  background: rgba(9, 25, 58, 0.43);

  &:hover {
    border-color: #dcdfe6;
    color: #dcdfe6;
  }
}

:deep(.el-upload:focus) {
  border-color: #dcdfe6;
  color: #dcdfe6;
}

// 作战描述 el-textarea样式
:deep(.el-textarea__inner) {
  background: rgba(9, 25, 58, 0.43);
  color: #fff;

  &:focus {
    border-color: #dcdfe6;
  }
}
:deep(.disableUpload) {
  div {
    display: none;
  }
}
</style>
<style>
.el-input.is-disabled .el-input__inner,
.el-textarea.is-disabled .el-textarea__inner {
  background-color: rgba(0, 117, 169, 0.2) !important;
  border-color: rgba(0, 117, 169, 0.7) !important;
  color: #fff !important;
}
</style>
